package au.edu.utas.yu_qiao_group.luckyman.service;

import android.database.sqlite.SQLiteDatabase;
import android.icu.text.SimpleDateFormat;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import au.edu.utas.yu_qiao_group.luckyman.db.draws.DrawListDTO;
import au.edu.utas.yu_qiao_group.luckyman.db.draws.DrawTable;
import au.edu.utas.yu_qiao_group.luckyman.db.draws.DrawDTO;
import au.edu.utas.yu_qiao_group.luckyman.db.raffles.RaffleDTO;
import au.edu.utas.yu_qiao_group.luckyman.db.tickets.TicketDTO;
import au.edu.utas.yu_qiao_group.luckyman.db.tickets.TicketTable;
import au.edu.utas.yu_qiao_group.luckyman.utils.RandomUtils;

public class DrawService {
  public static ArrayList<DrawListDTO> retrieveAll(SQLiteDatabase db) {
    return DrawTable.selectAll(db);
  }

  // normal raffle
  public static DrawListDTO runDraw (SQLiteDatabase db, DrawListDTO d) throws Exception {
    DrawListDTO result = null;
    String winnerNo = null;
    // normal
    ArrayList<TicketDTO> existingTickets = TicketService.retrieveAllByRaffleID(db, d.getMRaffleID());
    if (existingTickets.size() == 0) {
      throw new Exception("Cannnot Draw because No Ticket was sold!");
    }
    Set<String> existing = existingTickets.stream().map(i -> i.getMTicketNo()).collect(Collectors.toSet());
       winnerNo = generateNormalTicketNo(TicketTable.TICKET_NO_LENGTH, existing);
    db.beginTransaction();
    try {
      TicketDTO winner = TicketTable.getByNO(db, d.getMRaffleID(), winnerNo);
      // has winner
      if (winner != null) {
        winner.setMJackpotFlag(1);
        d.setMStatus(DrawDTO.STATUS_FINISHED);
        d.setMWinnerTicketNo(winnerNo);
        d.setMWinnerPhone(winner.getMCustomerPhone());
        DrawTable.update(db, d);
        TicketTable.update(db, winner);
      } else {
        // no winner
        d.setMStatus(DrawDTO.STATUS_FINISHED);
        d.setMWinnerTicketNo(winnerNo);
        DrawTable.update(db, d);
      }
      result = d;
      db.setTransactionSuccessful();
    } catch (Exception e) {
      throw new Exception("update winner info failed!");
    }
    db.endTransaction();
    return result;
  }

  // margin raffle
  public static DrawListDTO runDraw (SQLiteDatabase db, DrawListDTO d, String n) throws Exception {
    DrawListDTO result = null;
    String winnerNo = TextUtils.equals(n, "0") ? "1000" : n;
    while (winnerNo.length() < TicketTable.TICKET_NO_LENGTH) {
      winnerNo = "0" + winnerNo;
    }
    db.beginTransaction();
    try {
      TicketDTO winner = TicketTable.getByNO(db, d.getMRaffleID(), winnerNo);
      // has winner
      if (winner != null) {
        winner.setMJackpotFlag(1);
        d.setMStatus(DrawDTO.STATUS_FINISHED);
        d.setMWinnerTicketNo(winnerNo);
        d.setMWinnerPhone(winner.getMCustomerPhone());
        DrawTable.update(db, d);
        TicketTable.update(db, winner);
      } else {
        // no winner
        d.setMStatus(DrawDTO.STATUS_FINISHED);
        d.setMWinnerTicketNo(winnerNo);
        DrawTable.update(db, d);
      }
      result = d;
      db.setTransactionSuccessful();
    } catch (Exception e) {
      throw new Exception("update winner info failed!");
    }
    db.endTransaction();
    return result;
  }

  public static boolean insertDraw(SQLiteDatabase db, RaffleDTO r) {
    boolean result = false;
    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddhhmmss");
    DrawDTO d = new DrawDTO();
    d.setMRaffleID(r.getMRaffleID());
    d.setMStatus(DrawDTO.STATUS_PENDING);
    d.setMDrawNo(formatter.format(new Date()) + RandomUtils.getRandom(6));
    d.setMDrawTime(r.getMDrawTime());
    d.setMDrawMethod(r.getMDrawMethod());
    try {
      DrawTable.insert(db, d);
      result = true;
    } catch (Exception e) {
      System.out.print(e);
    }
    return result;
  }

  public static boolean cancelDraw(SQLiteDatabase db, RaffleDTO r) {
    boolean result = false;
    DrawDTO d = DrawTable.getByRaffID(db, r.getMRaffleID());
    // if doesn't exist, no need to delete
    if (d == null) {
      return true;
    }
    switch (d.getMStatus()) {
      // only pending status can be cancelled
      case DrawDTO.STATUS_PENDING:
        d.setMStatus(DrawDTO.STATUS_CANCELLED);
        break;
      case DrawDTO.STATUS_FINISHED:
      case DrawDTO.STATUS_CANCELLED:
      default:
        return true;
    }
    try {
      DrawTable.update(db, d);
      result = true;
    } catch (Exception e) {
      System.out.print(e);
    }
    return result;
  }

  public static boolean cancelDraw(SQLiteDatabase db, DrawListDTO d) {
    boolean result = false;
    switch (d.getMStatus()) {
      // only pending status can be cancelled
      case DrawDTO.STATUS_PENDING:
        d.setMStatus(DrawDTO.STATUS_CANCELLED);
        break;
      case DrawDTO.STATUS_FINISHED:
      case DrawDTO.STATUS_CANCELLED:
      default:
        return true;
    }
    try {
      DrawTable.update(db, d);
      result = true;
    } catch (Exception e) {
      System.out.print(e);
    }
    return result;
  }

//  private static String generateMarginTicketNo(int len) {
//    String newTicketNo = RandomUtils.getRandom(len - 1);
//    newTicketNo = (newTicketNo == "000" ? "1" : "0") + newTicketNo;
//    return newTicketNo;
//  }

  private static String generateNormalTicketNo(int len, Set<String> include) {
    String newTicketNo = RandomUtils.getRandom(len - 1);
    newTicketNo = (newTicketNo == "000" ? "1" : "0") + newTicketNo;
    while (include.contains(newTicketNo) == false) {
      newTicketNo = RandomUtils.getRandom(len - 1);
      newTicketNo = (newTicketNo == "000" ? "1" : "0") + newTicketNo;
    }
    return newTicketNo;
  }
}


